/**
 * Copyright (C) 2011-2012 GreenSoft S.A.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ar.com.greensoft.jeecommons.web.jsf.searching;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.faces.context.FacesContext;

import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.ExtendedDataModel;
import org.ajax4jsf.model.Range;
import org.ajax4jsf.model.SequenceRange;

import ar.com.greensoft.jeecommons.web.jsf.AbstractCrudFacadeBean;
import ar.com.greensoft.neosystem.dao.DaoException;
import ar.com.greensoft.neosystem.dao.searching.DtoSearchableDao;
import ar.com.greensoft.neosystem.dao.searching.EntityDto;
import ar.com.greensoft.neosystem.dao.searching.SortCriteria;
import ar.com.greensoft.neosystem.search.SearchFilter;

/**
 *
 * @author Jorge E. Villaverde
 * @since 1.0.0
 * @version 1.0.0
 */
public class EntityDataModel<Dto extends EntityDto>
	extends ExtendedDataModel<Dto>
	implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -7368053342459824351L;

	private Long rowKey = null;
	private int rowCount = -1;
	private List<Dto> cache = null;
	private int currentRow = -1;
	private int rows = -1;
	private DtoSearchableDao<Dto> dao;
	private SearchFilter filter;
	private List<SortCriteria> sortCriterias;	
	
	// -------------------- CONSTRUCTOR----------------------------------------
	
	public EntityDataModel(DtoSearchableDao<Dto> dao, SearchFilter filter) {
		super();
		this.dao = dao;
		this.filter = filter;
		reset();
	}
	
	@Override
	public Object getRowKey() {
		return rowKey;
	}

	@Override
	public void setRowKey(Object rowKey) {
		this.rowKey = (Long)rowKey;
	}

	@Override
	public void walk(FacesContext fc, DataVisitor dv, Range range, Object o) {
        SequenceRange sr = (SequenceRange) range;
        int currentRow = sr.getFirstRow();
        int rows = sr.getRows();
        
		try {
			if(this.currentRow != currentRow || this.rows != rows || this.cache == null){
				if(filter != null){
					this.cache = dao.findDtoEntriesBySearchFilter(filter, 
							currentRow, rows, this.sortCriterias );
				}else{
					this.cache = dao.findDtoEntries(currentRow, rows, this.sortCriterias);
				}
				if(cache == null){
					this.rowCount = -1;
					this.rows = 0;
					return;
				}else{
					if(this.rowCount <= 0){
						this.rowCount = cache.size();
					}
				}
			}
			if(cache == null){
				this.currentRow = -1;
				this.rows = 0;
				return;
			}
	        for (Dto t : cache) {
	        	dv.process(fc, t.getId(), o);
	        }
		} catch (DaoException e) {
			AbstractCrudFacadeBean.addErrorMessage(e.getMessage());
		}
		this.currentRow = currentRow;
		this.rows = rows;
	}

	@Override
	public int getRowCount() {
		if(rowCount == -1){
			try {
				if(filter != null){
					rowCount = (int)dao.countDtoBySearchFilter(filter);
				}else {
					rowCount = (int)dao.countDto();
				}
			} catch (DaoException e) {
				AbstractCrudFacadeBean.addErrorMessage(e.getMessage());
			}
		}
		return rowCount;
	}

	@Override
	public Dto getRowData() {
		for(Dto t : cache){
			if(t.getId().equals(rowKey))
				return t;
		}
		return null;
	}

	@Override
	public int getRowIndex() {
		return -1;
	}

	@Override
	public Object getWrappedData() {
		throw new UnsupportedOperationException();
	}

	@Override
	public boolean isRowAvailable() {
		return rowKey != null;
	}

	@Override
	public void setRowIndex(int arg0) {
		throw new UnsupportedOperationException();
	}

	@Override
	public void setWrappedData(Object arg0) {
		throw new UnsupportedOperationException();
	}

	public void reset() {
		this.rowKey = null;
		this.rowCount = -1;
		this.cache = null;
		this.currentRow = -1;
		this.rows = -1;
		this.sortCriterias = new ArrayList<SortCriteria>();
	}	

	public List<SortCriteria> getSortCriterias() {
		return sortCriterias;
	}

	public void setSortCriterias(List<SortCriteria> sortCriterias) {
		this.sortCriterias = sortCriterias;
	}
}
